package com.ahdy.service;

import com.ahdy.model.JsonParse;
import com.ahdy.model.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
public class SparkAiService {

    // 讯飞星火API配置
    private static final String HOST_URL = "https://spark-api.xf-yun.com/v4.0/chat";
    private static final String DOMAIN = "4.0Ultra";
    private static final String APP_ID = "e165b70d";
    private static final String API_SECRET = "MTBlM2EwMjA5NjAxMDEzNWZlMDBkZDJl";
    private static final String API_KEY = "60fc45cf4c9f18357c1d3b27c7371ec0";

    // 系统提示词
    private static final String SYSTEM_PROMPT = "你是一个专业的医生，会根据病人提出的问题，给与专业的有利于康复的活动、可操作的活动 字数控制在150字左右";

    // 会话历史存储（实际项目中应该使用数据库）
    private final Map<String, List<RoleContent>> sessionHistories = new ConcurrentHashMap<>();

    private final Gson gson = new Gson();
    private final OkHttpClient httpClient = new OkHttpClient.Builder().build();

    /**
     * 流式聊天
     */
    public SseEmitter chatStream(String message, String sessionId) {
        SseEmitter emitter = new SseEmitter(30000L); // 30秒超时
        log.info("开始流式聊天，会话ID: {}, 消息长度: {} 字符", sessionId, message.length());

        try {
            // 确保输入消息是UTF-8编码
            String utf8Message = ensureUtf8(message);

            // 获取或创建会话历史
            List<RoleContent> history = getOrCreateSessionHistory(sessionId);

            // 添加用户消息到历史（确保UTF-8编码）
            history.add(new RoleContent("user", utf8Message));

            // 构建WebSocket连接
            String authUrl = getAuthUrl(HOST_URL, API_KEY, API_SECRET);
            String wsUrl = authUrl.replace("http://", "ws://").replace("https://", "wss://");
            Request request = new Request.Builder().url(wsUrl).build();

            // 创建WebSocket监听器
            WebSocketListener listener = new WebSocketListener() {
                private StringBuilder totalAnswer = new StringBuilder();

                @Override
                public void onOpen(WebSocket webSocket, Response response) {
                    log.info("WebSocket连接已建立");
                    // WebSocket连接成功，发送请求
                    try {
                        JSONObject requestJson = buildRequest(history, utf8Message);
                        String requestStr = requestJson.toString();

                        // 确保请求数据是UTF-8编码
                        byte[] utf8Bytes = requestStr.getBytes(StandardCharsets.UTF_8);
                        String utf8RequestStr = new String(utf8Bytes, StandardCharsets.UTF_8);

                        webSocket.send(utf8RequestStr);
                        log.debug("发送请求: {}", utf8RequestStr.length() > 200 ?
                                utf8RequestStr.substring(0, 200) + "..." : utf8RequestStr);
                    } catch (Exception e) {
                        log.error("发送WebSocket请求失败: {}", e.getMessage());
                        emitter.completeWithError(e);
                    }
                }

                @Override
                public void onMessage(WebSocket webSocket, String text) {
                    try {
                        // 确保接收到的文本是UTF-8编码
                        String utf8Text = ensureUtf8(text);
                        log.debug("接收到WebSocket消息: {}", utf8Text.length() > 100 ?
                                utf8Text.substring(0, 100) + "..." : utf8Text);

                        JsonParse jsonParse = gson.fromJson(utf8Text, JsonParse.class);

                        if (jsonParse.getHeader().getCode() != 0) {
                            log.error("API返回错误，错误码: {}", jsonParse.getHeader().getCode());
                            emitter.completeWithError(new RuntimeException("API错误，错误码：" + jsonParse.getHeader().getCode()));
                            return;
                        }

                        // 处理返回的文本
                        List<Text> textList = jsonParse.getPayload().getChoices().getText();
                        for (Text temp : textList) {
                            String content = temp.getContent();

                            // 确保内容是UTF-8编码并清理
                            String utf8Content = ensureUtf8(content);
                            String cleanContent = cleanTextContent(utf8Content);

                            totalAnswer.append(cleanContent);

                            // 发送流式数据（确保UTF-8编码）
                            ChatResponse response = new ChatResponse(cleanContent, sessionId, false);
                            String responseJson = gson.toJson(response);
                            String utf8ResponseJson = ensureUtf8(responseJson);

                            emitter.send(SseEmitter.event()
                                    .name("message")
                                    .data(utf8ResponseJson));

                            log.debug("发送内容块: {}", cleanContent.length() > 50 ?
                                    cleanContent.substring(0, 50) + "..." : cleanContent);
                        }

                        // 检查是否完成
                        if (jsonParse.getHeader().getStatus() == 2) {
                            // 添加助手回复到历史（确保UTF-8编码和清理）
                            String finalAnswer = finalTextClean(totalAnswer.toString());
                            history.add(new RoleContent("assistant", finalAnswer));

                            // 管理历史记录长度
                            manageHistorySize(history);

                            // 发送完成信号
                            ChatResponse finalResponse = new ChatResponse("", sessionId, true);
                            String finalResponseJson = gson.toJson(finalResponse);
                            String utf8FinalResponseJson = ensureUtf8(finalResponseJson);

                            emitter.send(SseEmitter.event()
                                    .name("finish")
                                    .data(utf8FinalResponseJson));

                            log.info("流式聊天完成，回答长度: {} 字符", finalAnswer.length());
                            emitter.complete();
                            webSocket.close(1000, "");
                        }
                    } catch (Exception e) {
                        log.error("处理WebSocket消息失败: {}", e.getMessage());
                        emitter.completeWithError(e);
                    }
                }

                @Override
                public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                    log.error("WebSocket连接失败: {}", t.getMessage());
                    emitter.completeWithError(t);
                }
            };

            // 建立WebSocket连接
            httpClient.newWebSocket(request, listener);

        } catch (Exception e) {
            log.error("启动流式聊天失败: {}", e.getMessage());
            emitter.completeWithError(e);
        }

        return emitter;
    }

    /**
     * 普通聊天（非流式）- 基于流式实现，等待完整响应
     */
    public ChatResponse chat(String message, String sessionId) {
        log.info("开始非流式聊天，会话ID: {}, 消息长度: {} 字符", sessionId, message.length());

        try {
            // 确保输入消息是UTF-8编码
            String utf8Message = ensureUtf8(message);

            // 获取或创建会话历史
            List<RoleContent> history = getOrCreateSessionHistory(sessionId);

            // 添加用户消息到历史（确保UTF-8编码）
            history.add(new RoleContent("user", utf8Message));

            // 构建WebSocket连接
            String authUrl = getAuthUrl(HOST_URL, API_KEY, API_SECRET);
            String wsUrl = authUrl.replace("http://", "ws://").replace("https://", "wss://");
            Request request = new Request.Builder().url(wsUrl).build();

            // 使用同步方式等待完整响应
            final StringBuilder totalAnswer = new StringBuilder();
            final Object waitLock = new Object();
            final boolean[] completed = {false};
            final Exception[] error = {null};

            // 创建WebSocket监听器
            WebSocketListener listener = new WebSocketListener() {
                @Override
                public void onOpen(WebSocket webSocket, Response response) {
                    log.info("非流式WebSocket连接已建立");
                    try {
                        JSONObject requestJson = buildRequest(history, utf8Message);
                        String requestStr = requestJson.toString();

                        // 确保请求数据是UTF-8编码
                        byte[] utf8Bytes = requestStr.getBytes(StandardCharsets.UTF_8);
                        String utf8RequestStr = new String(utf8Bytes, StandardCharsets.UTF_8);

                        webSocket.send(utf8RequestStr);
                        log.debug("发送非流式请求完成");
                    } catch (Exception e) {
                        log.error("发送非流式WebSocket请求失败: {}", e.getMessage());
                        error[0] = e;
                        synchronized (waitLock) {
                            completed[0] = true;
                            waitLock.notify();
                        }
                    }
                }

                @Override
                public void onMessage(WebSocket webSocket, String text) {
                    try {
                        // 确保接收到的文本是UTF-8编码
                        String utf8Text = ensureUtf8(text);
                        log.debug("接收到非流式WebSocket消息");

                        JsonParse jsonParse = gson.fromJson(utf8Text, JsonParse.class);

                        if (jsonParse.getHeader().getCode() != 0) {
                            log.error("非流式API返回错误，错误码: {}", jsonParse.getHeader().getCode());
                            error[0] = new RuntimeException("API错误，错误码：" + jsonParse.getHeader().getCode());
                            synchronized (waitLock) {
                                completed[0] = true;
                                waitLock.notify();
                            }
                            return;
                        }

                        // 处理返回的文本
                        List<Text> textList = jsonParse.getPayload().getChoices().getText();
                        for (Text temp : textList) {
                            String content = temp.getContent();

                            // 确保内容是UTF-8编码并清理
                            String utf8Content = ensureUtf8(content);
                            String cleanContent = cleanTextContent(utf8Content);

                            totalAnswer.append(cleanContent);
                            log.debug("累积非流式内容，当前长度: {}", totalAnswer.length());
                        }

                        // 检查是否完成
                        if (jsonParse.getHeader().getStatus() == 2) {
                            log.info("非流式聊天完成，总回答长度: {} 字符", totalAnswer.length());
                            synchronized (waitLock) {
                                completed[0] = true;
                                waitLock.notify();
                            }
                            webSocket.close(1000, "");
                        }
                    } catch (Exception e) {
                        log.error("处理非流式WebSocket消息失败: {}", e.getMessage());
                        error[0] = e;
                        synchronized (waitLock) {
                            completed[0] = true;
                            waitLock.notify();
                        }
                    }
                }

                @Override
                public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                    log.error("非流式WebSocket连接失败: {}", t.getMessage());
                    error[0] = t instanceof Exception ? (Exception) t : new RuntimeException(t);
                    synchronized (waitLock) {
                        completed[0] = true;
                        waitLock.notify();
                    }
                }
            };

            // 建立WebSocket连接
            httpClient.newWebSocket(request, listener);

            // 等待响应完成（最多30秒）
            synchronized (waitLock) {
                long startTime = System.currentTimeMillis();
                while (!completed[0] && (System.currentTimeMillis() - startTime) < 30000) {
                    try {
                        waitLock.wait(1000); // 每秒检查一次
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        throw new RuntimeException("等待响应被中断", e);
                    }
                }
            }

            // 检查是否超时
            if (!completed[0]) {
                throw new RuntimeException("等待AI响应超时（30秒）");
            }

            // 检查是否有错误
            if (error[0] != null) {
                throw error[0];
            }

            // 处理完整响应
            String finalAnswer = finalTextClean(totalAnswer.toString());

            if (finalAnswer.trim().isEmpty()) {
                throw new RuntimeException("AI返回空响应");
            }

            // 添加助手回复到历史
            history.add(new RoleContent("assistant", finalAnswer));

            // 管理历史记录长度
            manageHistorySize(history);

            log.info("非流式聊天成功完成，最终回答长度: {} 字符", finalAnswer.length());
            return new ChatResponse(finalAnswer, sessionId, true);

        } catch (Exception e) {
            log.error("非流式聊天失败: {}", e.getMessage());
            throw new RuntimeException("聊天服务错误: " + e.getMessage(), e);
        }
    }

    /**
     * 确保字符串是UTF-8编码 - 参考DeepSeek的实现
     */
    private String ensureUtf8(String input) {
        if (input == null) {
            return "";
        }

        try {
            // 检测字符串是否已经是正确的UTF-8编码
            byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
            String reconstructed = new String(bytes, StandardCharsets.UTF_8);

            // 如果重构后的字符串与原字符串相同，说明编码正确
            if (reconstructed.equals(input)) {
                return input;
            }

            // 尝试从ISO-8859-1转换为UTF-8（常见的乱码情况）
            byte[] isoBytes = input.getBytes(StandardCharsets.ISO_8859_1);
            String utf8String = new String(isoBytes, StandardCharsets.UTF_8);

            log.debug("字符编码转换: '{}' -> '{}'", input, utf8String);
            return utf8String;

        } catch (Exception e) {
            log.warn("字符编码转换失败，返回原始字符串: {}", e.getMessage());
            return input;
        }
    }

    /**
     * 清理文本内容 - 参考DeepSeek的实现
     */
    private String cleanTextContent(String content) {
        if (content == null || content.trim().isEmpty()) {
            return "";
        }

        // 直接返回内容，减少不必要的处理
        String cleaned = content.trim();

        // 只移除明显的控制字符，保留所有正常字符
        cleaned = cleaned.replaceAll("[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]", "");

        log.debug("清理文本: '{}' (长度: {})", cleaned, cleaned.length());

        return cleaned;
    }

    /**
     * 最终文本清理（用于完整文本）- 参考DeepSeek的实现
     */
    private String finalTextClean(String fullText) {
        if (fullText == null || fullText.trim().isEmpty()) {
            return "";
        }

        // 确保UTF-8编码
        String cleaned = ensureUtf8(fullText);

        // 1. 基础清理
        cleaned = cleanTextContent(cleaned);

        // 2. 处理段落结构
        cleaned = cleaned.replaceAll("\n\\s*\n\\s*\n", "\n\n"); // 统一段落间距

        // 3. 确保句子间合适的间距
        cleaned = cleaned.replaceAll("([。！？])([^\\s\n])", "$1 $2");

        // 4. 清理开头和结尾的特殊字符，但保留中文
        cleaned = cleaned.replaceAll("^[^\\u4e00-\\u9fa5a-zA-Z0-9]+", "");
        cleaned = cleaned.replaceAll("[^\\u4e00-\\u9fa5a-zA-Z0-9。！？]+$", "");

        return cleaned.trim();
    }

    /**
     * 获取或创建会话历史
     */
    private List<RoleContent> getOrCreateSessionHistory(String sessionId) {
        return sessionHistories.computeIfAbsent(sessionId, k -> {
            List<RoleContent> history = new ArrayList<>();
            // 添加系统提示词（确保UTF-8编码）
            history.add(new RoleContent("system", ensureUtf8(SYSTEM_PROMPT)));
            return history;
        });
    }

    /**
     * 管理历史记录长度
     */
    private void manageHistorySize(List<RoleContent> history) {
        int totalLength = history.stream()
                .mapToInt(roleContent -> roleContent.getContent().length())
                .sum();

        // 如果历史记录太长，删除一些旧的对话（保留系统提示词）
        while (totalLength > 12000 && history.size() > 3) {
            // 删除最旧的用户-助手对话（跳过系统提示词）
            if (history.size() > 1) {
                history.remove(1); // 删除第一个用户消息
            }
            if (history.size() > 1) {
                history.remove(1); // 删除对应的助手回复
            }

            totalLength = history.stream()
                    .mapToInt(roleContent -> roleContent.getContent().length())
                    .sum();
        }

        log.debug("历史记录管理完成，当前长度: {}, 条目数: {}", totalLength, history.size());
    }

    /**
     * 构建请求JSON
     */
    private JSONObject buildRequest(List<RoleContent> history, String newMessage) {
        JSONObject requestJson = new JSONObject();

        // header参数
        JSONObject header = new JSONObject();
        header.put("app_id", APP_ID);
        header.put("uid", UUID.randomUUID().toString().substring(0, 10));

        // parameter参数
        JSONObject parameter = new JSONObject();
        JSONObject chat = new JSONObject();
        chat.put("domain", DOMAIN);
        chat.put("temperature", 0.5);
        chat.put("max_tokens", 4096);
        parameter.put("chat", chat);

        // payload参数
        JSONObject payload = new JSONObject();
        JSONObject message = new JSONObject();
        JSONArray text = new JSONArray();

        // 添加历史消息（确保UTF-8编码）
        for (RoleContent roleContent : history) {
            // 确保内容是UTF-8编码
            RoleContent utf8RoleContent = new RoleContent(
                    roleContent.getRole(),
                    ensureUtf8(roleContent.getContent())
            );
            text.add(JSON.toJSON(utf8RoleContent));
        }

        message.put("text", text);
        payload.put("message", message);

        requestJson.put("header", header);
        requestJson.put("parameter", parameter);
        requestJson.put("payload", payload);

        return requestJson;
    }

    /**
     * 生成鉴权URL
     */
    private String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {
        URL url = new URL(hostUrl);

        // 时间
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());

        // 拼接
        String preStr = "host: " + url.getHost() + "\n" +
                "date: " + date + "\n" +
                "GET " + url.getPath() + " HTTP/1.1";

        // SHA256加密
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
        mac.init(spec);

        byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));

        // Base64加密
        String sha = Base64.getEncoder().encodeToString(hexDigits);

        // 拼接
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                apiKey, "hmac-sha256", "host date request-line", sha);

        // 拼接地址
        HttpUrl httpUrl = Objects.requireNonNull(HttpUrl.parse("https://" + url.getHost() + url.getPath()))
                .newBuilder()
                .addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8)))
                .addQueryParameter("date", date)
                .addQueryParameter("host", url.getHost())
                .build();

        return httpUrl.toString();
    }

    /**
     * 清除会话历史
     */
    public void clearSession(String sessionId) {
        sessionHistories.remove(sessionId);
        log.info("清除会话历史: {}", sessionId);
    }

    /**
     * 获取会话历史
     */
    public List<RoleContent> getSessionHistory(String sessionId) {
        List<RoleContent> history = sessionHistories.getOrDefault(sessionId, new ArrayList<>());
        log.debug("获取会话历史: {}, 条目数: {}", sessionId, history.size());
        return history;
    }
}
